{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# WebCam (USB) Camera Test"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this notebook, you can test your camera to make sure it's working on the Jetson Nano as expected.  It should already be plugged into the USB camera port.  Make sure there is no obstruction on the camera lens such as a film or cover."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Check to see if the device is available\n",
    "Execute the following system command to list all video devices on the Jetson Nano.  If your camera doesn't show up with a device id, check your connection.  You should get an output similar to \n",
    "```text\n",
    "crw-rw----+ 1 root video 81, 0 Jun  2 17:35 /dev/video0\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls -ltrh /dev/video*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create the camera object\n",
    "\n",
    "First, create a camera object by importing the `USBCamera` class from the library by executing the following Python code cell.  Please note, you can only create one `USBCamera` instance. Set the `capture_device=` to the correct number found when you listed the system video devices.  If you have `/dev/video0`, then set `capture_device=0`.  If you have `/dev/video1`, set `capture_device=1` in the code line below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from jetcam.usb_camera import USBCamera\n",
    "\n",
    "#TODO change capture_device if incorrect for your system\n",
    "camera = USBCamera(width=224, height=224, capture_width=640, capture_height=480, capture_device=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can then capture a frame from the camera with the `read` method. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "image = camera.read()\n",
    "\n",
    "print(image.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Calling the `read` method for `camera` also updates the camera's internal `value`.  By looking at the value's `shape`, we see three numbers representing the pixel height, pixel width, and number of color channels."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(camera.value.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create a widget to view the image stream\n",
    "We can create a \"widget\" to display this image in the notebook.  In order to see the image, convert it from its blue-green-red format (brg8) to a format the browser can display (jpeg). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ipywidgets\n",
    "from IPython.display import display\n",
    "from jetcam.utils import bgr8_to_jpeg\n",
    "\n",
    "image_widget = ipywidgets.Image(format='jpeg')\n",
    "\n",
    "image_widget.value = bgr8_to_jpeg(image)\n",
    "\n",
    "display(image_widget)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see an image from the camera if all is working correctly.  If there seems to be an image but it's fuzzy or a funny color, check to make sure there is no protective film or cap on the lens.  \n",
    "\n",
    "Now let's watch a live stream from the camera.  Set the `running` value of the camera to continuously update the value in background.  This allows you to attach \"callbacks\" to the camera value changes.\n",
    "\n",
    "The \"callback\" here is the function, `update_image`, which is attached by calling the `observe` method below.  `update_image` is executed whenever there is a new image available to process, which is then displayed in the widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "camera.running = True\n",
    "\n",
    "def update_image(change):\n",
    "    image = change['new']\n",
    "    image_widget.value = bgr8_to_jpeg(image)\n",
    "    \n",
    "camera.observe(update_image, names='value')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you move something in front of the camera, you should now see the live video stream in the widget. To stop it, unattach the callback with the `unobserve` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "camera.unobserve(update_image, names='value')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Another way to view the image stream\n",
    "You can also use the traitlets `dlink` method to connect the camera to the widget, using a transform as one of the parameters.  This eliminates some steps in the process."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import traitlets\n",
    "\n",
    "camera_link = traitlets.dlink((camera, 'value'), (image_widget, 'value'), transform=bgr8_to_jpeg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can remove the camera/widget link with the `unlink` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "camera_link.unlink()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "... and reconnect it again with `link`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "camera_link.link()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1 style=\"background-color:#76b900;\"></h1>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Before you go...<br><br>Shut down the camera and/or notebook kernel to release the camera resource"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Attention!  Execute this cell before moving to another notebook\n",
    "# The USB camera application only requires that the notebook be reset\n",
    "# The CSI camera application requires that the 'camera' object be specifically released\n",
    "\n",
    "import os\n",
    "os._exit(00)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
